//
//  BaseNetRequest.m
//  WeatherBar
//
//  Created by Bert on 2024/6/7.
//

#import "BaseNetRequest.h"
#import <libkern/OSAtomic.h>
#import <os/lock.h>
#import "AFNetworkReachabilityManager.h"
#import <AFNetworking/AFNetworking.h>

static NSMutableDictionary *instancesMapper;
static OSSpinLock spinlock = OS_SPINLOCK_INIT;
//static os_unfair_lock_t lock = &(OS_UNFAIR_LOCK_INIT);

@interface BaseNetRequest()

@property (nonatomic,strong) AFHTTPSessionManager *httpSessionManager;

@end


@implementation BaseNetRequest

- (id)init
{
    self = [super init];
    if (self){ //  @"application/json;charset=UTF-8"  @"application/x-www-form-urlencoded"
        self.httpSessionManager = [AFHTTPSessionManager manager];
        self.httpSessionManager.requestSerializer.timeoutInterval = kAFNetworkingTimeoutInterval;

//        self.httpSessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        self.httpSessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
//        [self.httpSessionManager.requestSerializer setValue:@"application/json;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
//        [self.httpSessionManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        self.httpSessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
        self.httpSessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",
            @"text/plain",
            @"text/javascript",
            @"text/json",
            @"text/html",
            @"image/jpeg", nil];
    }
    return self;
}

+ (instancetype)sharedInstance {
    if (@available(iOS 10.0, *)) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instancesMapper = [NSMutableDictionary dictionary];
        });
        
        os_unfair_lock_t lock = &(OS_UNFAIR_LOCK_INIT);
        //    os_unfair_lock_trylock(lock);
        os_unfair_lock_lock(lock);
        id instance = instancesMapper[NSStringFromClass(self)];
        if (!instance) {
            instance = [self new];
            instancesMapper[NSStringFromClass(self)] = instance;
        }
        os_unfair_lock_unlock(lock);
        
        return instance;
    }
    else
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instancesMapper = [NSMutableDictionary dictionary];
        });
        
        OSSpinLockLock(&spinlock);
        
        __block id instance = instancesMapper[NSStringFromClass(self)];
        if (!instance) {
            instance = [self new];
            instancesMapper[NSStringFromClass(self)] = instance;
        }
        OSSpinLockUnlock(&spinlock);
        return instance;
    }
}

#pragma mark - 网络状态监控
/**
 *  开始检测网络连接
 */
+(void)startNetMonitoring{
    [AFNetworkReachabilityManager sharedManager];
    [[AFNetworkReachabilityManager sharedManager] startMonitoring];
}
/**
 *  停止检测网络连接
 */
+(void)stopNetMonitoring{
    [[AFNetworkReachabilityManager sharedManager]stopMonitoring];
}

#pragma mark - 初始化网络访问参数
-(void)updateSessionManagerHeaderFields:(NSDictionary *)sessionManagerParameters timeoutInterval:(NSTimeInterval)timeoutInterval
{
    for (NSString *key in sessionManagerParameters.allKeys) {
        [self.httpSessionManager.requestSerializer setValue:sessionManagerParameters[key] forHTTPHeaderField:key];
    }
}

-(void)updateSessionManagerHeaderFields:(NSDictionary *)sessionManagerParameters
{
    //默认60秒
    [self updateSessionManagerHeaderFields:sessionManagerParameters timeoutInterval:kAFNetworkingTimeoutInterval];
}

#pragma mark - 网络数据访问
//配置根域名
- (void)requestWithType:(RequestType)type
                    url:(NSString *)urlString
             parameters:(NSDictionary *)parameters
                success:(BaseNetRequestSuccessBlock)success
                failure:(BaseNetRequestFailureBlock)failure
{
    if (!self.BaseUrl) {
        if (failure) {
            NSError *err = [NSError errorWithDomain:kBaseNetRequestErrorDomain code:-9999 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Net Request BaseUrl is null!",nil]];
            
            failure(err);
        }
        return;
    }
    
    //包含百分号的字符串转译
    urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//    NSURL *fullUrl = [NSURL URLWithString:urlString relativeToURL:[NSURL URLWithString:self.BaseUrl]];
    
    NSString *urlStr = [NSString stringWithFormat:@"%@%@",self.BaseUrl,urlString];
    NSURL *fullUrl = [NSURL URLWithString:urlStr];
    switch (type) {
        case RequestTypePost:
        {
            [self postWithFullUrl:fullUrl.absoluteString parameters:parameters success:success failure:failure];
            break;
        }
        case RequestTypeGet:
        {
            [self getWithFullUrl:fullUrl.absoluteString parameters:parameters success:success failure:failure];
            break;
        }
        case RequestTypePut:
        {
            [self putWithFullUrl:fullUrl.absoluteString parameters:parameters success:success failure:failure];
            break;
        }
        case RequestTypeDelete:
        {
            [self deleteWithFullUrl:fullUrl.absoluteString parameters:parameters success:success failure:failure];
            break;
        }
        default:
            break;
    }
}
#pragma mark === 真正请求：POST
- (void)postWithFullUrl:(NSString *)fullURLString parameters:(NSDictionary *)parameters success:(BaseNetRequestSuccessBlock )success failure:(BaseNetRequestFailureBlock )failure
{
    if (@available(iOS 9.0, *)) {
       fullURLString = [fullURLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    }else {
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
        fullURLString = [fullURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        #pragma clang diagnostic pop
    }
    

    #if kIsPrintLog && defined(DEBUG)
    NSDictionary *headerDic = [self.httpSessionManager.requestSerializer valueForKey:@"mutableHTTPRequestHeaders"];
    #endif

    [self.httpSessionManager POST:fullURLString parameters:parameters headers:@{} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStylePOST,fullURLString,headerDic,parameters,responseObject);
        #endif
        
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStylePOST,fullURLString,headerDic,parameters,error);
        #endif
        
        if (failure) {
            failure(error);
        }
    }];
}

#pragma mark === 真正请求：GET
- (void)getWithFullUrl:(NSString *)fullURLString parameters:(NSDictionary *)parameters success:(BaseNetRequestSuccessBlock )success failure:(BaseNetRequestFailureBlock )failure
{
    if (@available(iOS 9.0, *)) {
       fullURLString = [fullURLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    }else {
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
        fullURLString = [fullURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        #pragma clang diagnostic pop
    }
    #if kIsPrintLog && defined(DEBUG)
    NSDictionary *headerDic = [self.httpSessionManager.requestSerializer valueForKey:@"mutableHTTPRequestHeaders"];
    #endif

    [self.httpSessionManager GET:fullURLString parameters:parameters headers:@{} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyleGET,fullURLString,headerDic,parameters,responseObject);
        #endif
        
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyleGET,fullURLString,headerDic,parameters,error);
        #endif
        if (failure) {
            failure(error);
        }
    }];
}
#pragma mark === 真正请求：PUT
- (void)putWithFullUrl:(NSString *)fullURLString parameters:(NSDictionary *)parameters success:(BaseNetRequestSuccessBlock )success failure:(BaseNetRequestFailureBlock )failure
{
    if (@available(iOS 9.0, *)) {
       fullURLString = [fullURLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    }else {
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
        fullURLString = [fullURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        #pragma clang diagnostic pop
    }
    #if kIsPrintLog && defined(DEBUG)
    NSDictionary *headerDic = [self.httpSessionManager.requestSerializer valueForKey:@"mutableHTTPRequestHeaders"];
    #endif

    [self.httpSessionManager PUT:fullURLString parameters:parameters headers:@{} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStylePUT,fullURLString,headerDic,parameters,responseObject);
        #endif
        
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStylePUT,fullURLString,headerDic,parameters,error);
        #endif
        if (failure) {
            failure(error);
        }
    }];
}

#pragma mark === 真正请求：DELETE
- (void)deleteWithFullUrl:(NSString *)fullURLString parameters:(NSDictionary *)parameters success:(BaseNetRequestSuccessBlock )success failure:(BaseNetRequestFailureBlock )failure
{
    if (@available(iOS 9.0, *)) {
       fullURLString = [fullURLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    }else {
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
        fullURLString = [fullURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        #pragma clang diagnostic pop
    }
    #if kIsPrintLog && defined(DEBUG)
    NSDictionary *headerDic = [self.httpSessionManager.requestSerializer valueForKey:@"mutableHTTPRequestHeaders"];
    #endif
    [self.httpSessionManager DELETE:fullURLString parameters:parameters headers:@{} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyleDELETE,fullURLString,headerDic,parameters,responseObject);
        #endif
        
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyleDELETE,fullURLString,headerDic,parameters,error);
        #endif
        if (failure) {
            failure(error);
        }
    }];
}

-(void)cancelDataTask
{
    NSMutableArray *dataTasks = [NSMutableArray arrayWithArray:[self httpSessionManager].dataTasks];
    for (NSURLSessionDataTask *taskObj in dataTasks) {
        [taskObj cancel];
    }
}

#pragma mark - 网络upload 访问方法
-(void)upLoadWithPOST:(NSString *)urlString
           parameters:(NSDictionary *)parameters
                image:(NSData *)img
             progress:(BaseNetRequestUploadProgressBlock)progress
              success:(BaseNetRequestSuccessBlock)success
              failure:(BaseNetRequestFailureBlock)failure
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyy-MM-dd";
    NSString *fileName = [NSString stringWithFormat:@"%@-%d.png",[formatter stringFromDate:[NSDate date]],1];
    
    #if kIsPrintLog && defined(DEBUG)
    NSDictionary *headerDic = [self.httpSessionManager.requestSerializer valueForKey:@"mutableHTTPRequestHeaders"];
    #endif
    NSURL *fullUrl = [NSURL URLWithString:urlString relativeToURL:[NSURL URLWithString:self.BaseUrl]];
    
    NSURLSessionDataTask *uploadTask =
    [self.httpSessionManager POST:fullUrl.absoluteString parameters:parameters headers:@{} constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
//        NSData *imgData = UIImageJPEGRepresentation(img, 1.0);
        [formData appendPartWithFileData:img name:@"file" fileName:fileName mimeType:@"image/jpeg"];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyle1,urlString,headerDic,parameters,responseObject);
        #endif
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyle1,urlString,headerDic,parameters,error);
        #endif
        if (failure) {
            failure(error);
        }
    }];
    [uploadTask resume];
}

-(void)upLoadWithPOST:(NSString *)urlString
           parameters:(NSDictionary *)parameters
                image:(NSData *)img
            imageName:(NSString *)imageName
             fileName:(NSString *)fileName
             progress:(BaseNetRequestUploadProgressBlock )progress
              success:(BaseNetRequestSuccessBlock)success
              failure:(BaseNetRequestFailureBlock)failure
{

    #if kIsPrintLog && defined(DEBUG)
    NSDictionary *headerDic = [self.httpSessionManager.requestSerializer valueForKey:@"mutableHTTPRequestHeaders"];
    #endif
    NSURL *fullUrl = [NSURL URLWithString:urlString relativeToURL:[NSURL URLWithString:self.BaseUrl]];
    NSURLSessionDataTask *uploadTask =
    [self.httpSessionManager POST:fullUrl.absoluteString parameters:parameters headers:@{} constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
//        NSData *imgData = UIImageJPEGRepresentation(img, 0.8);
        [formData appendPartWithFileData:img name:imageName fileName:fileName mimeType:@"image/jpeg"];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyle1,urlString,headerDic,parameters,responseObject);
        #endif
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyle1,urlString,headerDic,parameters,error);
        #endif
        if (failure) {
            failure(error);
        }
    }];
    [uploadTask resume];
}

-(void)upLoadWithPOST:(NSString *)urlString
           parameters:(NSDictionary *)parameters
           imageArray:(NSArray *)imageArray
             progress:(BaseNetRequestUploadProgressBlock )progress
              success:(BaseNetRequestSuccessBlock)success
              failure:(BaseNetRequestFailureBlock)failure
{
    #if kIsPrintLog && defined(DEBUG)
    NSDictionary *headerDic = [self.httpSessionManager.requestSerializer valueForKey:@"mutableHTTPRequestHeaders"];
    #endif
    NSURL *fullUrl = [NSURL URLWithString:urlString relativeToURL:[NSURL URLWithString:self.BaseUrl]];
    NSURLSessionDataTask *uploadTask =
    [self.httpSessionManager POST:fullUrl.absoluteString parameters:parameters headers:@{} constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        for (NSData *img in imageArray) {
//            NSData *imgData = UIImageJPEGRepresentation(img, 1.0);
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            formatter.dateFormat = @"yyyy-MM-dd";
            NSString *fileName = [NSString stringWithFormat:@"%@-%ld.png",[formatter stringFromDate:[NSDate date]],(unsigned long)[imageArray indexOfObject:img]];
            [formData appendPartWithFileData:img name:@"file" fileName:fileName mimeType:@"image/jpeg"];
        }
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyle1,urlString,headerDic,parameters,responseObject);
        #endif
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        #if kIsPrintLog && defined(DEBUG)
        NFRLog(kPrintDebugSuccessStyle1,urlString,headerDic,parameters,error);
        #endif
        if (failure) {
            failure(error);
        }
    }];
    [uploadTask resume];
}

-(void)cancelUploadTask
{
    NSMutableArray *uploadTasks = [NSMutableArray arrayWithArray:[self httpSessionManager].uploadTasks];
    for (NSURLSessionDataTask *taskObj in uploadTasks) {
        [taskObj cancel];
    }
}

#pragma mark - 网络Download 访问方法
- (void)downLoadWithURL:(NSString *)fullURLString progress:(BaseNetRequestSuccessBlock)progress destination:(BaseNetRequestDestinationBlock )destination downLoadSuccess:(BaseNetRequestDownLoadSuccessBlock )downLoadSuccess failure:(BaseNetRequestFailureBlock)failure
{
    NSURL *url = [NSURL URLWithString:fullURLString];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    NSURLSessionDownloadTask *task =
    [self.httpSessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        if (progress) {
            progress(downloadProgress);
        }
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        if (destination) {
            return destination(targetPath, response);
        }else{
            return nil;
        }
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        if (!error) {
            #if kIsPrintLog && defined(DEBUG)
                NSLog(kPrintDebugSuccessStyle2,fullURLString,response);
            #endif
            downLoadSuccess(response, filePath);
        }else{
            #if kIsPrintLog && defined(DEBUG)
                NSLog(kPrintDebugFailureStyle1,fullURLString,error);
            #endif
            failure(error);
        }
    }];
    
    [task resume];
}

-(void)cancelDownloadTask
{
    NSMutableArray *downloadTasks = [NSMutableArray arrayWithArray:[self httpSessionManager].downloadTasks];
    for (NSURLSessionDataTask *taskObj in downloadTasks) {
        [taskObj cancel];
    }
}

#pragma mark - 公共方法
-(void)cancelAllTask
{
    [self cancelDataTask];
    [self cancelUploadTask];
    [self cancelDownloadTask];
}

@end
